# frozen_string_literal: true

require 'spec_helper'

RSpec.describe MergeRequests::CreateFromVulnerabilityDataService, '#execute', feature_category: :vulnerability_management do
  let(:remediations_folder) { Rails.root.join('ee/spec/fixtures/security_reports/remediations') }
  let(:yarn_lock_content) { File.read(File.join(remediations_folder, "yarn.lock")) }
  let(:remediation_patch_content) { File.read(File.join(remediations_folder, "remediation.patch")) }

  let(:group)   { create(:group) }
  let(:user)    { create(:user) }
  let(:project) do
    create(:project, :custom_repo, namespace: group, files: { 'yarn.lock' => yarn_lock_content })
  end

  before do
    group.add_developer(user)
  end

  shared_examples 'a created merge_request' do
    let(:result) { described_class.new(project, user, params).execute }

    it 'creates the merge_request with the given params' do
      expect(result[:status]).to eq(:success)
      merge_request = result[:merge_request]
      expect(merge_request).to be_persisted
      expect(merge_request.project).to eq(project)
      expect(merge_request.author).to eq(user)
      expect(merge_request.title).to eq(expected_title)
      expect(merge_request.description).to eq(expected_description)
      expect(merge_request.target_branch).to eq(project.default_branch)
      expect(merge_request.source_branch).to start_with('remediate/authentication-bypass-via-incorrect-dom-traversal-and-canonical')
    end
  end

  context 'when user does not have permission to create merge_request' do
    let(:result) { described_class.new(project, user, { title: 'title', category: 'dependency_scanning' }).execute }

    before do
      allow_any_instance_of(described_class).to receive(:can?).with(user, :create_merge_request_in, project).and_return(false)
      allow_any_instance_of(described_class).to receive(:can?).with(user, :create_merge_request_from, project).and_return(false)
    end

    it 'returns expected error' do
      expect(result[:status]).to eq(:error)
      expect(result[:message]).to eq("User is not permitted to create merge request")
    end
  end

  context 'when merge_requests are disabled on project' do
    let(:result) { described_class.new(project, user, { title: 'title', category: 'dependency_scanning' }).execute }
    let(:project) { create(:project, namespace: group, merge_requests_access_level: ProjectFeature::DISABLED) }

    it 'returns expected error' do
      expect(result[:status]).to eq(:error)
      expect(result[:message]).to eq("User is not permitted to create merge request")
    end
  end

  context 'when params are valid' do
    context 'when category is dependency scanning' do
      let(:diff) do
        Base64.encode64(remediation_patch_content)
      end

      context 'when a description is present' do
        let(:params) do
          {
            category: "dependency_scanning",
            name: "Authentication bypass via incorrect DOM traversal and canonicalization in saml2-js",
            description: "Some XML DOM traversal and canonicalization APIs may be inconsistent in handling of comments within XML nodes. Incorrect use of these APIs by some SAML libraries results in incorrect parsing of the inner text of XML nodes such that any inner text after the comment is lost prior to cryptographically signing the SAML message. Text after the comment therefore has no impact on the signature on the SAML message.\n\nA remote attacker can modify SAML content for a SAML service provider without invalidating the cryptographic signature, which may allow attackers to bypass primary authentication for the affected SAML service provider.",
            cve: "yarn.lock:saml2-js:gemnasium:9952e574-7b5b-46fa-a270-aeb694198a98",
            severity: "Unknown",
            solution: "Upgrade to fixed version.",
            scanner: {
              id: "gemnasium",
              name: "Gemnasium"
            },
            location: {
              file: "yarn.lock",
              dependency: {
                package: {
                  name: "saml2-js"
                },
                version: "1.5.0"
              }
            },
            identifiers: [
              {
                type: "gemnasium",
                name: "Gemnasium-9952e574-7b5b-46fa-a270-aeb694198a98",
                value: "9952e574-7b5b-46fa-a270-aeb694198a98",
                url: "https://deps.sec.gitlab.com/packages/npm/saml2-js/versions/1.5.0/advisories"
              },
              {
                type: "cve",
                name: "CVE-2017-11429",
                value: "CVE-2017-11429",
                url: "https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2017-11429"
              }
            ],
            links: [
              {
                url: "https://github.com/Clever/saml2/commit/3546cb61fd541f219abda364c5b919633609ef3d#diff-af730f9f738de1c9ad87596df3f6de84R279"
              },
              {
                url: "https://github.com/Clever/saml2/issues/127"
              },
              {
                url: "https://www.kb.cert.org/vuls/id/475445"
              }
            ],
            project_fingerprint: "fa6f5b6c5d240b834ac5e901dc69f9484cef89ec",
            title: "Authentication bypass via incorrect DOM traversal and canonicalization in saml2-js",
            remediations: [
              {
                fixes: [
                  {
                    cve: "yarn.lock:saml2-js:gemnasium:9952e574-7b5b-46fa-a270-aeb694198a98"
                  }
                ],
                summary: "Upgrade saml2-js",
                diff: diff
              }
            ],
            path: "yarn.lock",
            urlPath: "/root/yarn-remediation/blob/9bade3fef995a9e2ca1de44d396b433864990ab9/yarn.lock"
          }
        end

        let(:expected_title) { 'Resolve vulnerability: Authentication bypass via incorrect DOM traversal and canonicalization in saml2-js' }
        let(:expected_description) do
          <<~DESC.chomp
            ### Description:

            Some XML DOM traversal and canonicalization APIs may be inconsistent in handling of comments within XML nodes. Incorrect use of these APIs by some SAML libraries results in incorrect parsing of the inner text of XML nodes such that any inner text after the comment is lost prior to cryptographically signing the SAML message. Text after the comment therefore has no impact on the signature on the SAML message.\n\nA remote attacker can modify SAML content for a SAML service provider without invalidating the cryptographic signature, which may allow attackers to bypass primary authentication for the affected SAML service provider.

            * Severity: Unknown
            * Location: [yarn.lock](yarn.lock)

            ### Solution:

            Upgrade to fixed version.

            ### Identifiers:

            * [Gemnasium-9952e574-7b5b-46fa-a270-aeb694198a98](https://deps.sec.gitlab.com/packages/npm/saml2-js/versions/1.5.0/advisories)
            * [CVE-2017-11429](https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2017-11429)

            ### Links:

            * https://github.com/Clever/saml2/commit/3546cb61fd541f219abda364c5b919633609ef3d#diff-af730f9f738de1c9ad87596df3f6de84R279
            * https://github.com/Clever/saml2/issues/127
            * https://www.kb.cert.org/vuls/id/475445
          DESC
        end

        it_behaves_like 'a created merge_request'
      end

      context 'when a description is NOT present' do
        let(:params) do
          {
            category: 'dependency_scanning',
            severity: "Unknown",
            solution: "Upgrade to fixed version.",
            file: "yarn.lock",
            cve: "yarn.lock:saml2-js:gemnasium:9952e574-7b5b-46fa-a270-aeb694198a98",
            title: 'Authentication bypass via incorrect DOM traversal and canonicalization in saml2-js',
            tool: 'find_sec_bugs',
            remediations: [
              { diff: diff }
            ]
          }
        end

        let(:expected_title) { 'Resolve vulnerability: Authentication bypass via incorrect DOM traversal and canonicalization in saml2-js' }
        let(:expected_description) do
          <<~DESC.chomp
            ### Description:

            Authentication bypass via incorrect DOM traversal and canonicalization in saml2-js

            * Severity: Unknown
            * Location: [yarn.lock](yarn.lock)

            ### Solution:

            Upgrade to fixed version.
          DESC
        end

        it_behaves_like 'a created merge_request'
      end
    end
  end

  context 'when params are invalid' do
    context 'when category is unknown' do
      let(:params) { { category: 'foo' } }
      let(:result) { described_class.new(project, user, params).execute }

      it 'return expected error' do
        expect(result[:status]).to eq(:error)
        expect(result[:message]).to eq('Invalid vulnerability category')
      end
    end

    context 'when remediations are missing' do
      let(:params) { { title: 'title', category: 'dependency_scanning', remediations: [] } }
      let(:result) { described_class.new(project, user, params).execute }

      it 'return expected error' do
        expect(result[:status]).to eq(:error)
        expect(result[:message]).to eq("No remediations available for merge request")
      end
    end
  end
end
